Setup

Load Libraries

library(tidyverse)
── Attaching core tidyverse packages ─────────────────────────────────────────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.1.0     ✔ readr     2.1.4
✔ forcats   1.0.0     ✔ stringr   1.5.0
✔ ggplot2   3.4.1     ✔ tibble    3.2.1
✔ lubridate 1.9.2     ✔ tidyr     1.3.0
✔ purrr     1.0.1     ── Conflicts ───────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
ℹ Use the ]8;;http://conflicted.r-lib.org/conflicted package]8;; to force all conflicts to become errors
library(here)
here() starts at /Users/stuartstenhouse/Codeclan/visit_scotland_codeclan_project
library(sf)
Linking to GEOS 3.11.0, GDAL 3.5.3, PROJ 9.1.0; sf_use_s2() is TRUE
library(infer)
library(ggridges)
library(modelr)
library(skimr)
library(ggfortify)

Run Cleaning Script, Read In Clean Data & Set Colour Scheme for Visualisations

source(here("scripts/cleaning_script.R"))

Attaching package: ‘janitor’

The following objects are masked from ‘package:stats’:

    chisq.test, fisher.test

Rows: 2673 Columns: 7── Column specification ───────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (6): FeatureCode, DateCode, Measurement, Units, Region of Residence, Breakdown of Domestic Tourism
dbl (1): Value
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.Rows: 32 Columns: 2── Column specification ───────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (2): feature_code, local_authority
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.Warning: One or more parsing issues, call `problems()` on your data frame for details, e.g.:
  dat <- vroom(...)
  problems(dat)Rows: 32082 Columns: 11── Column specification ───────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (6): Quarter, Country, Purpose, Mode, Duration, Age
dbl (4): Visits, Nights, Spend, Sample
num (1): Year
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.New names:Rows: 463 Columns: 7── Column specification ───────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (1): Local Authority
dbl (3): Year, Turnover, GVA
num (2): Business Units, Employment
lgl (1): ...7
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Reading layer `pub_las' from data source 
  `/Users/stuartstenhouse/Codeclan/visit_scotland_codeclan_project/data/geo_data' using driver `ESRI Shapefile'
Simple feature collection with 32 features and 3 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: 5512.998 ymin: 530250.8 xmax: 470332 ymax: 1220302
Projected CRS: OSGB36 / British National Grid
Rows: 11 Columns: 4── Column specification ───────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
dbl (1): year
num (3): visits, spend, nights
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.Warning: Each row in `x` is expected to match at most 1 row in `y`.Warning: Each row in `x` is expected to match at most 1 row in `y`.Warning: object 'dom_int_summary_clean' not found
regional_domestic_tourism_individual <- read_csv(here("data/clean_data/regional_domestic_tourism_individual_clean.csv"))
Rows: 288 Columns: 7── Column specification ───────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (4): feature_code, year, region_of_residence, local_authority
dbl (3): visits, nights, expenditure
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
regional_domestic_tourism_non_gb_clean <- read_csv(here("data/clean_data/regional_domestic_tourism_non_gb_clean.csv"))
Rows: 576 Columns: 7── Column specification ───────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (4): feature_code, year, region_of_residence, local_authority
dbl (3): visits, expenditure, nights
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
international_visits <- read_csv(here("data/clean_data/international_visits_clean.csv"))
Rows: 32082 Columns: 11── Column specification ───────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (6): quarter, country, purpose, mode, duration, age
dbl (5): year, visits, nights, spend, sample
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
tourism_businesses <- read_csv(here("data/clean_data/tourism_businesses_clean.csv"))
Rows: 462 Columns: 6── Column specification ───────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (1): local_authority
dbl (5): year, business_units, employment, turnover, gva
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
dom_int_summary <- read_csv(here("data/clean_data/dom_int_summary_clean.csv"))
Rows: 22 Columns: 4── Column specification ───────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (1): dom_int
dbl (3): year, visits, spend
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
local_authority_geo <- st_read(dsn = "data/geo_data/", layer = "pub_las")
Reading layer `pub_las' from data source 
  `/Users/stuartstenhouse/Codeclan/visit_scotland_codeclan_project/data/geo_data' using driver `ESRI Shapefile'
Simple feature collection with 32 features and 3 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: 5512.998 ymin: 530250.8 xmax: 470332 ymax: 1220302
Projected CRS: OSGB36 / British National Grid
colour_scheme <- c("#540453", "#1d1d65", "#970061", "#b6cb2b", "#9fd6f3")

Annual Average Stats

Domestic

5 Figure Summary

dom_int_summary %>%
  filter(dom_int == "Domestic") %>% 
  skim()
── Data Summary ────────────────────────
                           Values    
Name                       Piped data
Number of rows             11        
Number of columns          4         
_______________________              
Column type frequency:               
  character                1         
  numeric                  3         
________________________             
Group variables            None      
dom_int_summary %>%
  filter(dom_int == "International") %>% 
  skim()
── Data Summary ────────────────────────
                           Values    
Name                       Piped data
Number of rows             11        
Number of columns          4         
_______________________              
Column type frequency:               
  character                1         
  numeric                  3         
________________________             
Group variables            None      

IQR

dom_int_summary %>%
  filter(dom_int == "Domestic") %>%  
  summarise(visits_iqr= IQR(visits),
            expenditure_iqr= IQR(spend))
dom_int_summary %>%
  filter(dom_int == "International") %>%  
  summarise(visits_iqr= IQR(visits),
            expenditure_iqr= IQR(spend))

Median

dom_int_summary %>%
  filter(dom_int == "Domestic") %>%  
  summarise(median_visits = median(visits),
            median_spend = median(spend))
NA
dom_int_summary %>%
  filter(dom_int == "International") %>%  
  summarise(median_visits = median(visits),
            median_spend = median(spend))

Domestic Tourism

Average Visits By Region

regional_data_joined %>% 
  group_by(local_authority) %>% 
  summarise(mean_visits = mean(visits)) %>% 
  arrange(desc(mean_visits))
Simple feature collection with 32 features and 2 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: 5512.998 ymin: 530250.8 xmax: 470332 ymax: 1220302
Projected CRS: OSGB36 / British National Grid

regional_data_joined %>% 
  group_by(code) %>% 
  summarise(mean_visits = mean(visits)) %>% 
  ggplot(aes(fill = mean_visits)) + 
  geom_sf(colour = "white", linewidth = 0.04) +
  labs(
    x = "Longitude",
    y = "Latitude",
    title = "Average Annual Number of Domestic Vistors",
    subtitle = "By Region",
    fill = "Visits (Thousands)") +
  theme(panel.background = element_rect(fill = "white"),
        axis.text.x = element_blank(),
        axis.text.y = element_blank(),
        axis.ticks = element_blank(),
        rect = element_blank(),
        axis.title.x = element_blank(),
        axis.title.y = element_blank())

Expenditure by Region

regional_data_joined %>% 
  group_by(local_authority) %>% 
  summarise(mean_expenditure = mean(expenditure)) %>% 
  arrange(desc(mean_expenditure))
Simple feature collection with 32 features and 2 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: 5512.998 ymin: 530250.8 xmax: 470332 ymax: 1220302
Projected CRS: OSGB36 / British National Grid
regional_data_joined %>% 
  group_by(code) %>% 
  summarise(mean_exp = mean(expenditure)) %>% 
  ggplot(aes(fill = mean_exp)) + 
  geom_sf(colour = "white", linewidth = 0.04) +
  labs(
    x = "Longitude",
    y = "Latitude",
    title = "Average Annual Expenditure of Domestic Vistors",
    subtitle = "By Region",
    fill = "Expenditure (Million GBP)") +
    theme(panel.background = element_rect(fill = "white"),
        axis.text.x = element_blank(),
        axis.text.y = element_blank(),
        axis.ticks = element_blank(),
        rect = element_blank(),
        axis.title.x = element_blank(),
        axis.title.y = element_blank())

Expenditure Per Visit

Mean Expenditure Per Visit Plot
regional_domestic_tourism_individual %>%
  filter(visits != 0,
         expenditure != 0) %>% 
  mutate(exp_per_visit = expenditure / visits, rm.na = TRUE) %>%
  group_by(local_authority) %>% 
  summarise(mean_exp_per_visit = mean(exp_per_visit)) %>% 
  arrange(desc(mean_exp_per_visit)) %>%
  ggplot() +
  geom_col(aes(x = reorder(local_authority, mean_exp_per_visit), y = mean_exp_per_visit,
               fill = local_authority %in% c("City of Edinburgh", "Glasgow City", "Highland")),
           show.legend = FALSE, colour = "white") +
  scale_fill_manual(values = c("FALSE" = "grey80",
                               "TRUE" = colour_scheme[1])) +
  coord_flip() +
  labs(
    x = "Region",
    y = "Mean Expenditure per Visit (Million GBP / Thousand Visits)",
    title = "Domestic Tourism Mean Expenditure per Visit") +
  theme(plot.title = element_text(size = 15, face = "bold"),
        plot.subtitle = element_text(size = 10),
        panel.background = element_rect(fill = "white"),
        panel.grid = element_line(colour = "grey90", linetype = "blank"))

Nights Stayed

Plot
regional_domestic_tourism_individual %>% 
  mutate(nights_per_visit = nights / visits) %>% 
  group_by(local_authority) %>% 
  summarise(mean_nights_per_visit = mean(nights_per_visit, na.rm = TRUE)) %>%
  ggplot() +
  geom_col(aes(x = reorder(local_authority, mean_nights_per_visit), y = mean_nights_per_visit,
               fill = local_authority %in% c("Shetland Islands", "Orkney Islands", "Na h-Eileanan Siar",
                                             "City of Edinburgh", "Glasgow City", "Highland")),
           show.legend = FALSE, colour = "white") +
  scale_fill_manual(values = c("FALSE" = "grey80",
                               "TRUE" = colour_scheme[1])) +
  coord_flip() +
  labs(
    x = "Region",
    y = "Avg. Nights per Visit",
    title = "Domestic Tourism Avg. Nights per Visit") +
  theme(plot.title = element_text(size = 15, face = "bold"),
        plot.subtitle = element_text(size = 10),
        panel.background = element_rect(fill = "white"),
        panel.grid = element_line(colour = "grey90", linetype = "blank"))

Map
regional_data_joined %>%
  mutate(nights_per_visit = nights / visits) %>% 
  group_by(local_authority) %>% 
  summarise(mean_nights_per_visit = mean(nights_per_visit, na.rm = TRUE)) %>%
  ggplot(aes(fill = mean_nights_per_visit)) + 
  geom_sf(colour = "white", linewidth = 0.04) +
  labs(
    x = "Longitude",
    y = "Latitude",
    title = "Domestic Tourism Mean Nights per Visit",
    fill = "Mean Nights per Visit"
  ) +
  theme(panel.background = element_rect(fill = "white"),
        axis.text.x = element_blank(),
        axis.text.y = element_blank(),
        axis.ticks = element_blank(),
        rect = element_blank(),
        axis.title.x = element_blank(),
        axis.title.y = element_blank(),
        plot.title = element_text(size = 15, face = "bold"))

NA

Gross Value Added

tourism_businesses %>%
  filter(local_authority != "Scotland",
         year %in% c(2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019)) %>%
  group_by(local_authority) %>% 
  summarise(total_gva = sum(gva)) %>% 
  slice_max(total_gva, n = 5)
  
tourism_businesses %>%
  filter(local_authority %in% c("City of Edinburgh", "Glasgow City", "Aberdeen City",
                                "Highland", "Fife"),
         year %in% c(2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019)) %>%
  ggplot() +
  geom_boxplot(aes(x = gva, y = local_authority, fill = local_authority), 
               alpha = 0.8,
               show.legend = FALSE) +
  scale_fill_manual(values = colour_scheme) +
  scale_colour_manual(values = colour_scheme) +
  labs(
    x = "Gross Value Added (Million GBP)",
    y = "Local Authority",
    title = "Distribution of Annual Gross Value Added",
    subtitle = "Top 5 Regions: 2009-2019"
  ) +
  theme(plot.title = element_text(size = 15, face = "bold"),
        plot.subtitle = element_text(size = 10),
        panel.background = element_rect(fill = "white"),
        panel.grid = element_line(colour = "grey90", 
                                  linetype = "dashed"))

Scottish Based Tourism Compared To English Based Tourism

regional_data_joined_sco_eng %>% 
  filter(region_of_residence == "Scotland") %>%
  group_by(local_authority) %>%
  summarise(mean_visits = mean(visits)) %>% 
  ggplot(aes(fill = mean_visits)) + 
  geom_sf(colour = "white", linewidth = 0.04) +
  labs(
    x = "Longitude",
    y = "Latitude",
    title = "Average Annual Number of Scottish Based Vistors",
    subtitle = "By Region",
    fill = "Visits (Thousands)") +
  theme(panel.background = element_rect(fill = "white"),
        axis.text.x = element_blank(),
        axis.text.y = element_blank(),
        axis.ticks = element_blank(),
        rect = element_blank(),
        axis.title.x = element_blank(),
        axis.title.y = element_blank())

regional_data_joined_sco_eng %>% 
  filter(region_of_residence == "England") %>% 
  group_by(local_authority) %>%
  summarise(mean_visits = mean(visits)) %>% 
  ggplot(aes(fill = mean_visits)) + 
  geom_sf(colour = "white", linewidth = 0.04) +
  labs(
    x = "Longitude",
    y = "Latitude",
    title = "Average Annual Number of English Based Vistors",
    subtitle = "By Region",
    fill = "Visits (Thousands)") +
  theme(panel.background = element_rect(fill = "white"),
        axis.text.x = element_blank(),
        axis.text.y = element_blank(),
        axis.ticks = element_blank(),
        rect = element_blank(),
        axis.title.x = element_blank(),
        axis.title.y = element_blank())

Marketing Edinburgh to Domestic Tourists: Mini Case Study

Visits by Country of Residence
regional_domestic_tourism_non_gb_clean %>%
  filter(local_authority %in% c("City of Edinburgh")) %>% 
  ggplot(aes(x = visits, y = region_of_residence, fill = region_of_residence == "Scotland")) +
  geom_density_ridges(show.legend = FALSE, alpha = 0.5) +
  theme_ridges() +
  theme(axis.title.y = element_blank()) +
  scale_fill_manual(values = c("FALSE" = colour_scheme[2],
                               "TRUE" = colour_scheme[1])) +
  labs(
    title = "Distribution of Annual Visits by Country of Residence",
    subtitle = "Edinburgh",
    x = "Visits (Thousands)") +
  theme(plot.title = element_text(size = 15, face = "bold"),
        plot.subtitle = element_text(size = 13),
        panel.background = element_rect(fill = "white"),
        panel.grid = element_line(colour = "grey90", linetype = "dashed"),
        axis.text.y = element_text(face = "bold"))

Expenditure Per Visit by Country of Residence
regional_domestic_tourism_non_gb_clean %>%
  filter(local_authority %in% c("City of Edinburgh")) %>%
  mutate(exp_per_visit = expenditure / visits) %>% 
  ggplot(aes(x = exp_per_visit, y = region_of_residence, fill = region_of_residence == "Scotland")) +
  geom_density_ridges(show.legend = FALSE, alpha = 0.5) +
  theme_ridges() +
  theme(axis.title.y = element_blank()) +
  scale_fill_manual(values = c("FALSE" = colour_scheme[2],
                               "TRUE" = colour_scheme[1])) +
  labs(
    title = "Distribution of Expenditure per Visit by Country of Residence",
    subtitle = "Edinburgh",
    x = "Expenditure per Visit (Million GBP / Thousand Visits)") +
  theme(plot.title = element_text(size = 15, face = "bold"),
        plot.subtitle = element_text(size = 13),
        panel.background = element_rect(fill = "white"),
        panel.grid = element_line(colour = "grey90", linetype = "dashed"),
        axis.text.y = element_text(face = "bold"))

Nights by Country of Residence
regional_domestic_tourism_non_gb_clean %>%
  filter(local_authority %in% c("City of Edinburgh")) %>% 
  mutate(nights_per_visit = nights / visits) %>%
  ggplot(aes(x = nights_per_visit, y = region_of_residence, fill = region_of_residence == "Scotland")) +
  geom_density_ridges(show.legend = FALSE, alpha = 0.5) +
  theme_ridges() +
  theme(axis.title.y = element_blank()) +
  scale_fill_manual(values = c("FALSE" = colour_scheme[2],
                               "TRUE" = colour_scheme[1])) +
  labs(
    title = "Distribution of Nights by Country of Residence",
    subtitle = "Edinburgh",
    x = "Nights") +
  theme(plot.title = element_text(size = 15, face = "bold"),
        plot.subtitle = element_text(size = 13),
        panel.background = element_rect(fill = "white"),
        panel.grid = element_line(colour = "grey90", linetype = "dashed"),
        axis.text.y = element_text(face = "bold"))

Linear Model: Predict Expenditure by Visits
regional_domestic_tourism_non_gb_clean %>% 
  filter(local_authority == "City of Edinburgh",
         region_of_residence == "England") %>% 
  summarise(cor(expenditure, visits))
edinburgh_england <- regional_domestic_tourism_non_gb_clean %>% 
  filter(local_authority == "City of Edinburgh",
         region_of_residence == "England")
model_edinburgh <- lm(formula = expenditure ~ visits, data = edinburgh_england)
summary(model_edinburgh)

Call:
lm(formula = expenditure ~ visits, data = edinburgh_england)

Residuals:
    Min      1Q  Median      3Q     Max 
-24.193  -4.918   4.838   6.423  14.165 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)    
(Intercept) -493.61749   62.18315  -7.938 9.58e-05 ***
visits         0.62423    0.03945  15.824 9.76e-07 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 12.34 on 7 degrees of freedom
Multiple R-squared:  0.9728,    Adjusted R-squared:  0.9689 
F-statistic: 250.4 on 1 and 7 DF,  p-value: 9.756e-07
autoplot(model_edinburgh)

  • Residuals vs. Fitted (Tests Independence of Residuals): No strong evidence of a pattern.
  • Normal Q-Q (Tests Normality of Residuals): Distribution of standardised residuals appears fairly normal.
  • Scale-Location (Tests Constancy of Variation of Residuals): No strong evidence of funneling.
edinburgh_england %>%
  add_predictions(model_edinburgh) %>%
  add_residuals(model_edinburgh) %>% 
  ggplot(aes(x = visits, y = expenditure)) +
  geom_point() +
  geom_line(aes(y = pred), col = colour_scheme[3], size = 1) +
  labs(
    x = "Visits (Thousands)",
    y = "Expenditure (Million GBP)",
    title = "English Based Visitors To Edinburgh: Expenditure / Visits",
    subtitle = "Based On 3 Year Annual Averages Between 2009-2019")

Model: spend ~ visits

Interpretation: ~97% of the variation in expenditure can be explained by the number of visits.

Question: The largest increase in visitor numbers is from 2009-2011 Avg. to 2010-2012 Avg. ~6%. If this percentage increase in visits was replicated in based on the most recent set of figures resulting in ~1803 (Thousand) visitors - what would the model predict for expenditure?

Answer: If visits were increased as above, the model would predict expenditure of ~632 Million GBP (Low Estimate ~620, High Estimate ~644)

As calculated below.

Step 1. outcome = b0 + b1 * 1st Predictor

Step 2. expenditure = b0(intercept) + b1(coefficient) * 1st Predictor

Step 3. expenditure = b0(intercept) + b1(coefficient) * visits

Step 4. expenditure = -493.61749 + 0.62423 * 1803

Step 5. expenditure = ~632 (Low Estimate ~620, High Estimate ~644)

632 + c(-12.34, 12.34)
[1] 619.66 644.34

International Tourism

Total Visitors by Country of Residence

international_visits %>% 
  select(-c(quarter, age, sample)) %>%
  filter(year %in% c(2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019),
         purpose == "Holiday") %>% 
  group_by(country) %>% 
  summarise(total_visits = sum(visits)) %>%
  slice_max(total_visits, n = 20) %>% 
  ggplot(aes(x = reorder(country, total_visits), y = total_visits)) +
  geom_col(aes(x = reorder(country, total_visits), y = total_visits,
               fill = country %in% c("USA")),
           show.legend = FALSE, colour = "white") +
  scale_fill_manual(values = c("FALSE" = "grey60",
                               "TRUE" = colour_scheme[1])) +
  coord_flip() +
  ylim(0, 3200) +
  labs(
    x = "Country",
    y = "Total Visits (Thousands)",
    title = "International Tourism: Total Visits (2002-2009)",
    subtitle = "Top 20 (Holiday Only)") +
  theme(plot.title = element_text(size = 15, face = "bold"),
        plot.subtitle = element_text(size = 10),
        panel.background = element_rect(fill = "white"),
        panel.grid = element_line(colour = "grey90", linetype = "blank"))

Total Expenditure by Country of Residence

international_visits %>% 
  select(-c(quarter, age, sample)) %>%
  filter(year %in% c(2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019),
         purpose == "Holiday") %>% 
  group_by(country) %>% 
  summarise(total_spend = sum(spend)) %>%
  slice_max(total_spend, n = 20) %>% 
  ggplot() +
  geom_col(aes(x = reorder(country, total_spend), y = total_spend,
               fill = country %in% c("USA")),
           show.legend = FALSE, colour = "white") +
  scale_fill_manual(values = c("FALSE" = "grey60",
                               "TRUE" = colour_scheme[1])) +
  coord_flip() +
  labs(
    x = "Country",
    y = "Total Expenditure (Million GBP)",
    title = "International Tourism: Total Expenditure (2002-2009)",
    subtitle = "Top 20 (Holiday Only)") +
  theme(plot.title = element_text(size = 15, face = "bold"),
        plot.subtitle = element_text(size = 10),
        panel.background = element_rect(fill = "white"),
        panel.grid = element_line(colour = "grey90", linetype = "blank"))

Expenditure per Visit by Country of Residence

Bar Plot

international_visits %>% 
  select(-c(quarter, age, sample)) %>%
  filter(year %in% c(2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019),
         purpose == "Holiday") %>% 
  group_by(country) %>% 
  summarise(total_spend = sum(spend),
            total_visits = sum(visits),
            spend_per_visit = total_spend / total_visits) %>%
  filter(total_visits > 500) %>%
  ggplot() +
  geom_col(aes(x = reorder(country, spend_per_visit), y = spend_per_visit,
               fill = country %in% c("Australia", "China", "Canada")),
           show.legend = FALSE, colour = "white") +
  scale_fill_manual(values = c("FALSE" = "grey60",
                               "TRUE" = colour_scheme[1])) +
  coord_flip() +
  labs(
    x = "Country",
    y = "Total Expenditure (Million GBP) / Total Visits (Thousands)",
    title = "International Tourism: Total Expenditure per Visit (2002-2009)",
    subtitle = "Countries w/ Over 500 Thousand Total Visits (Holiday Only)") +
  theme(plot.title = element_text(size = 15, face = "bold"),
        plot.subtitle = element_text(size = 10),
        panel.background = element_rect(fill = "white"),
        panel.grid = element_line(colour = "grey90", linetype = "blank"))

Scatter Plot

international_visits %>% 
  select(-c(quarter, age, sample)) %>%
  filter(year %in% c(2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019),
         purpose == "Holiday") %>% 
  group_by(country) %>% 
  summarise(total_spend = sum(spend),
            total_visits = sum(visits),
            spend_per_visit = total_spend / total_visits) %>%
  filter(total_visits > 500) %>% 
  ggplot(aes(x = total_visits, y = spend_per_visit)) +
  geom_point(aes(colour = country %in% c("Australia", "China", "Canada")), 
             show.legend = FALSE,
             size = 4) +
  scale_colour_manual(values = c("FALSE" = "grey60",
                                 "TRUE" = colour_scheme[3])) +
  ggrepel::geom_text_repel(aes(x = total_visits, y = spend_per_visit, label = country)) +
  labs(
    x = "Visits (Thousands)",
    y = "Total Expenditure (Million GBP) / Total Visits (Thousands)",
    title = "International Tourism: Visits vs. Expenditure Per Visit (2002-2009)",
    subtitle = "Countries w/ Over 500 Thousand Total Visits (Holiday Only)") +
  theme(plot.title = element_text(size = 15, face = "bold"),
        plot.subtitle = element_text(size = 10),
        panel.background = element_rect(fill = "white"),
        panel.grid = element_line(colour = "grey90", linetype = "dashed"))

Marketing Scotland To Canadian Based Tourists

\(H_0\): \(\mu_{\textrm{spend per visit(Q1+Q4)}} - \mu_{\textrm{spend per visit(Q2+Q3)}} = 0\) \(H_a\): \(\mu_{\textrm{spend per visit(Q1+Q4)}} - \mu_{\textrm{spend per visit(Q2+Q3)}} != 0\)

international_visits %>%
  filter(country == "Canada",
         purpose == "Holiday") %>% 
  mutate(exp_per_visit = spend / visits,
         spring_summer = if_else(quarter %in% c("Quarter 2", "Quarter 3"), "Yes", "No")) %>%  
  group_by(spring_summer) %>% 
  summarise(mean_visits = mean(visits),
            mean_exp = mean(spend),
            mean_exp_per_visit = mean(exp_per_visit))
canada_sample <- international_visits %>%
  filter(country == "Canada",
         purpose == "Holiday") %>% 
  mutate(exp_per_visit = spend / visits,
         spring_summer = if_else(quarter %in% c("Quarter 2", "Quarter 3"), "Yes", "No"))
observed_stat <- canada_sample %>% 
  specify(exp_per_visit ~ spring_summer) %>%
  calculate(stat = "diff in means", order = c("Yes", "No"))

observed_stat
Response: exp_per_visit (numeric)
Explanatory: spring_summer (factor)
null_distribution <- canada_sample %>% 
  specify(response = exp_per_visit, explanatory = spring_summer) %>%
  hypothesize(null = "independence") %>%
  generate(reps = 1000, type = "permute") %>% 
  calculate(stat = "diff in means", order = c("Yes", "No"))
null_distribution %>%
  visualise() +
  shade_p_value(obs_stat = observed_stat, direction = "both")

null_distribution %>%
  get_p_value(obs_stat = observed_stat, direction = "both")
LS0tCnRpdGxlOiAiVmlzaXQgU2NvdGxhbmQgQW5hbHlzaXMiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMjIFNldHVwCgojIyMgTG9hZCBMaWJyYXJpZXMKCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShoZXJlKQpsaWJyYXJ5KHNmKQpsaWJyYXJ5KGluZmVyKQpsaWJyYXJ5KGdncmlkZ2VzKQpsaWJyYXJ5KG1vZGVscikKbGlicmFyeShza2ltcikKbGlicmFyeShnZ2ZvcnRpZnkpCmBgYAoKIyMjIFJ1biBDbGVhbmluZyBTY3JpcHQsIFJlYWQgSW4gQ2xlYW4gRGF0YSAmIFNldCBDb2xvdXIgU2NoZW1lIGZvciBWaXN1YWxpc2F0aW9ucwoKYGBge3J9CnNvdXJjZShoZXJlKCJzY3JpcHRzL2NsZWFuaW5nX3NjcmlwdC5SIikpCgpyZWdpb25hbF9kb21lc3RpY190b3VyaXNtX2luZGl2aWR1YWwgPC0gcmVhZF9jc3YoaGVyZSgiZGF0YS9jbGVhbl9kYXRhL3JlZ2lvbmFsX2RvbWVzdGljX3RvdXJpc21faW5kaXZpZHVhbF9jbGVhbi5jc3YiKSkKcmVnaW9uYWxfZG9tZXN0aWNfdG91cmlzbV9ub25fZ2JfY2xlYW4gPC0gcmVhZF9jc3YoaGVyZSgiZGF0YS9jbGVhbl9kYXRhL3JlZ2lvbmFsX2RvbWVzdGljX3RvdXJpc21fbm9uX2diX2NsZWFuLmNzdiIpKQppbnRlcm5hdGlvbmFsX3Zpc2l0cyA8LSByZWFkX2NzdihoZXJlKCJkYXRhL2NsZWFuX2RhdGEvaW50ZXJuYXRpb25hbF92aXNpdHNfY2xlYW4uY3N2IikpCnRvdXJpc21fYnVzaW5lc3NlcyA8LSByZWFkX2NzdihoZXJlKCJkYXRhL2NsZWFuX2RhdGEvdG91cmlzbV9idXNpbmVzc2VzX2NsZWFuLmNzdiIpKQpkb21faW50X3N1bW1hcnkgPC0gcmVhZF9jc3YoaGVyZSgiZGF0YS9jbGVhbl9kYXRhL2RvbV9pbnRfc3VtbWFyeV9jbGVhbi5jc3YiKSkKCmxvY2FsX2F1dGhvcml0eV9nZW8gPC0gc3RfcmVhZChkc24gPSAiZGF0YS9nZW9fZGF0YS8iLCBsYXllciA9ICJwdWJfbGFzIikKCmNvbG91cl9zY2hlbWUgPC0gYygiIzU0MDQ1MyIsICIjMWQxZDY1IiwgIiM5NzAwNjEiLCAiI2I2Y2IyYiIsICIjOWZkNmYzIikKYGBgCgojIyBBbm51YWwgQXZlcmFnZSBTdGF0cwoKIyMjIERvbWVzdGljCgojIyMjIDUgRmlndXJlIFN1bW1hcnkKCmBgYHtyfQpkb21faW50X3N1bW1hcnkgJT4lCiAgZmlsdGVyKGRvbV9pbnQgPT0gIkRvbWVzdGljIikgJT4lIAogIHNraW0oKQpgYGAKCmBgYHtyfQpkb21faW50X3N1bW1hcnkgJT4lCiAgZmlsdGVyKGRvbV9pbnQgPT0gIkludGVybmF0aW9uYWwiKSAlPiUgCiAgc2tpbSgpCmBgYAoKIyMjIyBJUVIKCmBgYHtyfQpkb21faW50X3N1bW1hcnkgJT4lCiAgZmlsdGVyKGRvbV9pbnQgPT0gIkRvbWVzdGljIikgJT4lICAKICBzdW1tYXJpc2UodmlzaXRzX2lxcj0gSVFSKHZpc2l0cyksCiAgICAgICAgICAgIGV4cGVuZGl0dXJlX2lxcj0gSVFSKHNwZW5kKSkKYGBgCgpgYGB7cn0KZG9tX2ludF9zdW1tYXJ5ICU+JQogIGZpbHRlcihkb21faW50ID09ICJJbnRlcm5hdGlvbmFsIikgJT4lICAKICBzdW1tYXJpc2UodmlzaXRzX2lxcj0gSVFSKHZpc2l0cyksCiAgICAgICAgICAgIGV4cGVuZGl0dXJlX2lxcj0gSVFSKHNwZW5kKSkKYGBgCgojIyMjIE1lZGlhbgoKYGBge3J9CmRvbV9pbnRfc3VtbWFyeSAlPiUKICBmaWx0ZXIoZG9tX2ludCA9PSAiRG9tZXN0aWMiKSAlPiUgIAogIHN1bW1hcmlzZShtZWRpYW5fdmlzaXRzID0gbWVkaWFuKHZpc2l0cyksCiAgICAgICAgICAgIG1lZGlhbl9zcGVuZCA9IG1lZGlhbihzcGVuZCkpCgpgYGAKCmBgYHtyfQpkb21faW50X3N1bW1hcnkgJT4lCiAgZmlsdGVyKGRvbV9pbnQgPT0gIkludGVybmF0aW9uYWwiKSAlPiUgIAogIHN1bW1hcmlzZShtZWRpYW5fdmlzaXRzID0gbWVkaWFuKHZpc2l0cyksCiAgICAgICAgICAgIG1lZGlhbl9zcGVuZCA9IG1lZGlhbihzcGVuZCkpCmBgYAoKIyMgVHJlbmRzIE92ZXIgVGltZQoKIyMjIE92ZXIgVGltZSAvIFZpc2l0cwoKYGBge3J9Cgpkb21faW50X3N1bW1hcnkgJT4lIAogIGdncGxvdCgpICsKICBnZW9tX2xpbmUoYWVzKHggPSB5ZWFyLCB5ID0gdmlzaXRzLCBjb2xvdXIgPSBkb21faW50KSwKICAgICAgICAgIHNpemUgPSAyKSArCiAgZ2VvbV9wb2ludChhZXMoeCA9IHllYXIsIHkgPSB2aXNpdHMsIGNvbG91ciA9IGRvbV9pbnQpLCAKICAgICAgICAgICAgIHNpemUgPSA0KSArCiAgeWxpbSgwLCAxNTAwMCkgKwogIGxhYnMoeCA9ICJcbiBZZWFyIiwKICAgICAgIHkgPSAiVmlzaXRvcnMgKFRob3VzYW5kcykgXG4iLAogICAgICAgdGl0bGUgPSAiQW5udWFsIFZpc2l0cyIsCiAgICAgICBzdWJ0aXRsZSA9ICJEb21lc3RpYyAmIEludGVybmF0aW9uYWwgT3Zlcm5pZ2h0IFZpc3RvcnMgKDIwMDktMjAxOSkiLAogICAgICAgY29sb3VyID0gIiIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gYygyMDA5LCAyMDEwLCAyMDExLCAyMDEyLCAyMDEzLCAyMDE0LCAyMDE1LCAyMDE2LCAyMDE3LCAyMDE4LCAyMDE5KSkgKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiRG9tZXN0aWMiID0gIiM1NDA0NTMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSW50ZXJuYXRpb25hbCIgPSAiIzlmZDZmMyIpKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUsIGZhY2UgPSAiYm9sZCIpLAogICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwKICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiKSwKICAgICAgICBwYW5lbC5ncmlkID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJncmV5OTAiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpbmV0eXBlID0gImRhc2hlZCIpKQoKYGBgCgojIyMgT3ZlciBUaW1lIC8gRXhwZW5kaXR1cmUKCmBgYHtyfQoKZG9tX2ludF9zdW1tYXJ5ICU+JSAKICBnZ3Bsb3QoKSArCiAgZ2VvbV9saW5lKGFlcyh4ID0geWVhciwgeSA9IHNwZW5kLCBjb2xvdXIgPSBkb21faW50KSwKICAgICAgICAgIHNpemUgPSAyKSArCiAgZ2VvbV9wb2ludChhZXMoeCA9IHllYXIsIHkgPSBzcGVuZCwgY29sb3VyID0gZG9tX2ludCksIAogICAgICAgICAgICAgc2l6ZSA9IDQpICsKICB5bGltKDAsIDQwMDApICsKICBsYWJzKHggPSAiXG4gWWVhciIsCiAgICAgICB5ID0gIkV4cGVuZGl0dXJlIChNaWxsaW9uIEdCUCkgXG4iLAogICAgICAgdGl0bGUgPSAiQW5udWFsIEV4cGVuZGl0dXJlIiwKICAgICAgIHN1YnRpdGxlID0gIkRvbWVzdGljICYgSW50ZXJuYXRpb25hbCBPdmVybmlnaHQgVmlzdG9ycyAoMjAwOS0yMDE5KSIsCiAgICAgICBjb2xvdXIgPSAiIikgKwogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBjKDIwMDksIDIwMTAsIDIwMTEsIDIwMTIsIDIwMTMsIDIwMTQsIDIwMTUsIDIwMTYsIDIwMTcsIDIwMTgsIDIwMTkpKSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJEb21lc3RpYyIgPSAiIzU0MDQ1MyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJJbnRlcm5hdGlvbmFsIiA9ICIjOWZkNmYzIikpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSwgZmFjZSA9ICJib2xkIiksCiAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIpLAogICAgICAgIHBhbmVsLmdyaWQgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImdyZXk5MCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGluZXR5cGUgPSAiZGFzaGVkIikpCgpgYGAKCiMjIERvbWVzdGljIFRvdXJpc20KCiMjIyMgQXZlcmFnZSBWaXNpdHMgQnkgUmVnaW9uCgpgYGB7cn0KcmVnaW9uYWxfZGF0YV9qb2luZWQgJT4lIAogIGdyb3VwX2J5KGxvY2FsX2F1dGhvcml0eSkgJT4lIAogIHN1bW1hcmlzZShtZWFuX3Zpc2l0cyA9IG1lYW4odmlzaXRzKSkgJT4lIAogIGFycmFuZ2UoZGVzYyhtZWFuX3Zpc2l0cykpCmBgYAoKYGBge3J9CgpyZWdpb25hbF9kYXRhX2pvaW5lZCAlPiUgCiAgZ3JvdXBfYnkoY29kZSkgJT4lIAogIHN1bW1hcmlzZShtZWFuX3Zpc2l0cyA9IG1lYW4odmlzaXRzKSkgJT4lIAogIGdncGxvdChhZXMoZmlsbCA9IG1lYW5fdmlzaXRzKSkgKyAKICBnZW9tX3NmKGNvbG91ciA9ICJ3aGl0ZSIsIGxpbmV3aWR0aCA9IDAuMDQpICsKICBsYWJzKAogICAgeCA9ICJMb25naXR1ZGUiLAogICAgeSA9ICJMYXRpdHVkZSIsCiAgICB0aXRsZSA9ICJBdmVyYWdlIEFubnVhbCBOdW1iZXIgb2YgRG9tZXN0aWMgVmlzdG9ycyIsCiAgICBzdWJ0aXRsZSA9ICJCeSBSZWdpb24iLAogICAgZmlsbCA9ICJWaXNpdHMgKFRob3VzYW5kcykiKSArCiAgdGhlbWUocGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIndoaXRlIiksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICByZWN0ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCkpCgpgYGAKCiMjIyMgRXhwZW5kaXR1cmUgYnkgUmVnaW9uCgpgYGB7cn0KcmVnaW9uYWxfZGF0YV9qb2luZWQgJT4lIAogIGdyb3VwX2J5KGxvY2FsX2F1dGhvcml0eSkgJT4lIAogIHN1bW1hcmlzZShtZWFuX2V4cGVuZGl0dXJlID0gbWVhbihleHBlbmRpdHVyZSkpICU+JSAKICBhcnJhbmdlKGRlc2MobWVhbl9leHBlbmRpdHVyZSkpCmBgYAoKCmBgYHtyfQpyZWdpb25hbF9kYXRhX2pvaW5lZCAlPiUgCiAgZ3JvdXBfYnkoY29kZSkgJT4lIAogIHN1bW1hcmlzZShtZWFuX2V4cCA9IG1lYW4oZXhwZW5kaXR1cmUpKSAlPiUgCiAgZ2dwbG90KGFlcyhmaWxsID0gbWVhbl9leHApKSArIAogIGdlb21fc2YoY29sb3VyID0gIndoaXRlIiwgbGluZXdpZHRoID0gMC4wNCkgKwogIGxhYnMoCiAgICB4ID0gIkxvbmdpdHVkZSIsCiAgICB5ID0gIkxhdGl0dWRlIiwKICAgIHRpdGxlID0gIkF2ZXJhZ2UgQW5udWFsIEV4cGVuZGl0dXJlIG9mIERvbWVzdGljIFZpc3RvcnMiLAogICAgc3VidGl0bGUgPSAiQnkgUmVnaW9uIiwKICAgIGZpbGwgPSAiRXhwZW5kaXR1cmUgKE1pbGxpb24gR0JQKSIpICsKICAgIHRoZW1lKHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcmVjdCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpKQpgYGAKCiMjIyMgRXhwZW5kaXR1cmUgUGVyIFZpc2l0CgojIyMjIyBNZWFuIEV4cGVuZGl0dXJlIFBlciBWaXNpdCBQbG90CgpgYGB7cn0KcmVnaW9uYWxfZG9tZXN0aWNfdG91cmlzbV9pbmRpdmlkdWFsICU+JQogIGZpbHRlcih2aXNpdHMgIT0gMCwKICAgICAgICAgZXhwZW5kaXR1cmUgIT0gMCkgJT4lIAogIG11dGF0ZShleHBfcGVyX3Zpc2l0ID0gZXhwZW5kaXR1cmUgLyB2aXNpdHMsIHJtLm5hID0gVFJVRSkgJT4lCiAgZ3JvdXBfYnkobG9jYWxfYXV0aG9yaXR5KSAlPiUgCiAgc3VtbWFyaXNlKG1lYW5fZXhwX3Blcl92aXNpdCA9IG1lYW4oZXhwX3Blcl92aXNpdCkpICU+JSAKICBhcnJhbmdlKGRlc2MobWVhbl9leHBfcGVyX3Zpc2l0KSkgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fY29sKGFlcyh4ID0gcmVvcmRlcihsb2NhbF9hdXRob3JpdHksIG1lYW5fZXhwX3Blcl92aXNpdCksIHkgPSBtZWFuX2V4cF9wZXJfdmlzaXQsCiAgICAgICAgICAgICAgIGZpbGwgPSBsb2NhbF9hdXRob3JpdHkgJWluJSBjKCJDaXR5IG9mIEVkaW5idXJnaCIsICJHbGFzZ293IENpdHkiLCAiSGlnaGxhbmQiKSksCiAgICAgICAgICAgc2hvdy5sZWdlbmQgPSBGQUxTRSwgY29sb3VyID0gIndoaXRlIikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIkZBTFNFIiA9ICJncmV5ODAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRSVUUiID0gY29sb3VyX3NjaGVtZVsxXSkpICsKICBjb29yZF9mbGlwKCkgKwogIGxhYnMoCiAgICB4ID0gIlJlZ2lvbiIsCiAgICB5ID0gIk1lYW4gRXhwZW5kaXR1cmUgcGVyIFZpc2l0IChNaWxsaW9uIEdCUCAvIFRob3VzYW5kIFZpc2l0cykiLAogICAgdGl0bGUgPSAiRG9tZXN0aWMgVG91cmlzbSBNZWFuIEV4cGVuZGl0dXJlIHBlciBWaXNpdCIpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSwgZmFjZSA9ICJib2xkIiksCiAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIpLAogICAgICAgIHBhbmVsLmdyaWQgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImdyZXk5MCIsIGxpbmV0eXBlID0gImJsYW5rIikpCmBgYAoKIyMjIyBOaWdodHMgU3RheWVkCgojIyMjIyBQbG90CgpgYGB7cn0KcmVnaW9uYWxfZG9tZXN0aWNfdG91cmlzbV9pbmRpdmlkdWFsICU+JSAKICBtdXRhdGUobmlnaHRzX3Blcl92aXNpdCA9IG5pZ2h0cyAvIHZpc2l0cykgJT4lIAogIGdyb3VwX2J5KGxvY2FsX2F1dGhvcml0eSkgJT4lIAogIHN1bW1hcmlzZShtZWFuX25pZ2h0c19wZXJfdmlzaXQgPSBtZWFuKG5pZ2h0c19wZXJfdmlzaXQsIG5hLnJtID0gVFJVRSkpICU+JQogIGdncGxvdCgpICsKICBnZW9tX2NvbChhZXMoeCA9IHJlb3JkZXIobG9jYWxfYXV0aG9yaXR5LCBtZWFuX25pZ2h0c19wZXJfdmlzaXQpLCB5ID0gbWVhbl9uaWdodHNfcGVyX3Zpc2l0LAogICAgICAgICAgICAgICBmaWxsID0gbG9jYWxfYXV0aG9yaXR5ICVpbiUgYygiU2hldGxhbmQgSXNsYW5kcyIsICJPcmtuZXkgSXNsYW5kcyIsICJOYSBoLUVpbGVhbmFuIFNpYXIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ2l0eSBvZiBFZGluYnVyZ2giLCAiR2xhc2dvdyBDaXR5IiwgIkhpZ2hsYW5kIikpLAogICAgICAgICAgIHNob3cubGVnZW5kID0gRkFMU0UsIGNvbG91ciA9ICJ3aGl0ZSIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJGQUxTRSIgPSAiZ3JleTgwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJUUlVFIiA9IGNvbG91cl9zY2hlbWVbMV0pKSArCiAgY29vcmRfZmxpcCgpICsKICBsYWJzKAogICAgeCA9ICJSZWdpb24iLAogICAgeSA9ICJBdmcuIE5pZ2h0cyBwZXIgVmlzaXQiLAogICAgdGl0bGUgPSAiRG9tZXN0aWMgVG91cmlzbSBBdmcuIE5pZ2h0cyBwZXIgVmlzaXQiKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUsIGZhY2UgPSAiYm9sZCIpLAogICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwKICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiKSwKICAgICAgICBwYW5lbC5ncmlkID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJncmV5OTAiLCBsaW5ldHlwZSA9ICJibGFuayIpKQpgYGAKCiMjIyMjIE1hcAoKYGBge3J9CnJlZ2lvbmFsX2RhdGFfam9pbmVkICU+JQogIG11dGF0ZShuaWdodHNfcGVyX3Zpc2l0ID0gbmlnaHRzIC8gdmlzaXRzKSAlPiUgCiAgZ3JvdXBfYnkobG9jYWxfYXV0aG9yaXR5KSAlPiUgCiAgc3VtbWFyaXNlKG1lYW5fbmlnaHRzX3Blcl92aXNpdCA9IG1lYW4obmlnaHRzX3Blcl92aXNpdCwgbmEucm0gPSBUUlVFKSkgJT4lCiAgZ2dwbG90KGFlcyhmaWxsID0gbWVhbl9uaWdodHNfcGVyX3Zpc2l0KSkgKyAKICBnZW9tX3NmKGNvbG91ciA9ICJ3aGl0ZSIsIGxpbmV3aWR0aCA9IDAuMDQpICsKICBsYWJzKAogICAgeCA9ICJMb25naXR1ZGUiLAogICAgeSA9ICJMYXRpdHVkZSIsCiAgICB0aXRsZSA9ICJEb21lc3RpYyBUb3VyaXNtIE1lYW4gTmlnaHRzIHBlciBWaXNpdCIsCiAgICBmaWxsID0gIk1lYW4gTmlnaHRzIHBlciBWaXNpdCIKICApICsKICB0aGVtZShwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHJlY3QgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSwgZmFjZSA9ICJib2xkIikpCiAgCmBgYAoKIyMjIyBHcm9zcyBWYWx1ZSBBZGRlZAoKYGBge3J9CnRvdXJpc21fYnVzaW5lc3NlcyAlPiUKICBmaWx0ZXIobG9jYWxfYXV0aG9yaXR5ICE9ICJTY290bGFuZCIsCiAgICAgICAgIHllYXIgJWluJSBjKDIwMDksIDIwMTAsIDIwMTEsIDIwMTIsIDIwMTMsIDIwMTQsIDIwMTUsIDIwMTYsIDIwMTcsIDIwMTgsIDIwMTkpKSAlPiUKICBncm91cF9ieShsb2NhbF9hdXRob3JpdHkpICU+JSAKICBzdW1tYXJpc2UodG90YWxfZ3ZhID0gc3VtKGd2YSkpICU+JSAKICBzbGljZV9tYXgodG90YWxfZ3ZhLCBuID0gNSkKICAKdG91cmlzbV9idXNpbmVzc2VzICU+JQogIGZpbHRlcihsb2NhbF9hdXRob3JpdHkgJWluJSBjKCJDaXR5IG9mIEVkaW5idXJnaCIsICJHbGFzZ293IENpdHkiLCAiQWJlcmRlZW4gQ2l0eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkhpZ2hsYW5kIiwgIkZpZmUiKSwKICAgICAgICAgeWVhciAlaW4lIGMoMjAwOSwgMjAxMCwgMjAxMSwgMjAxMiwgMjAxMywgMjAxNCwgMjAxNSwgMjAxNiwgMjAxNywgMjAxOCwgMjAxOSkpICU+JQogIGdncGxvdCgpICsKICBnZW9tX2JveHBsb3QoYWVzKHggPSBndmEsIHkgPSBsb2NhbF9hdXRob3JpdHksIGZpbGwgPSBsb2NhbF9hdXRob3JpdHkpLCAKICAgICAgICAgICAgICAgYWxwaGEgPSAwLjgsCiAgICAgICAgICAgICAgIHNob3cubGVnZW5kID0gRkFMU0UpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjb2xvdXJfc2NoZW1lKSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjb2xvdXJfc2NoZW1lKSArCiAgbGFicygKICAgIHggPSAiR3Jvc3MgVmFsdWUgQWRkZWQgKE1pbGxpb24gR0JQKSIsCiAgICB5ID0gIkxvY2FsIEF1dGhvcml0eSIsCiAgICB0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgQW5udWFsIEdyb3NzIFZhbHVlIEFkZGVkIiwKICAgIHN1YnRpdGxlID0gIlRvcCA1IFJlZ2lvbnM6IDIwMDktMjAxOSIKICApICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSwgZmFjZSA9ICJib2xkIiksCiAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIpLAogICAgICAgIHBhbmVsLmdyaWQgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImdyZXk5MCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGluZXR5cGUgPSAiZGFzaGVkIikpCmBgYAoKIyMjIyBTY290dGlzaCBCYXNlZCBUb3VyaXNtIENvbXBhcmVkIFRvIEVuZ2xpc2ggQmFzZWQgVG91cmlzbQoKYGBge3J9CnJlZ2lvbmFsX2RhdGFfam9pbmVkX3Njb19lbmcgJT4lIAogIGZpbHRlcihyZWdpb25fb2ZfcmVzaWRlbmNlID09ICJTY290bGFuZCIpICU+JQogIGdyb3VwX2J5KGxvY2FsX2F1dGhvcml0eSkgJT4lCiAgc3VtbWFyaXNlKG1lYW5fdmlzaXRzID0gbWVhbih2aXNpdHMpKSAlPiUgCiAgZ2dwbG90KGFlcyhmaWxsID0gbWVhbl92aXNpdHMpKSArIAogIGdlb21fc2YoY29sb3VyID0gIndoaXRlIiwgbGluZXdpZHRoID0gMC4wNCkgKwogIGxhYnMoCiAgICB4ID0gIkxvbmdpdHVkZSIsCiAgICB5ID0gIkxhdGl0dWRlIiwKICAgIHRpdGxlID0gIkF2ZXJhZ2UgQW5udWFsIE51bWJlciBvZiBTY290dGlzaCBCYXNlZCBWaXN0b3JzIiwKICAgIHN1YnRpdGxlID0gIkJ5IFJlZ2lvbiIsCiAgICBmaWxsID0gIlZpc2l0cyAoVGhvdXNhbmRzKSIpICsKICB0aGVtZShwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHJlY3QgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSkKYGBgCgpgYGB7cn0KcmVnaW9uYWxfZGF0YV9qb2luZWRfc2NvX2VuZyAlPiUgCiAgZmlsdGVyKHJlZ2lvbl9vZl9yZXNpZGVuY2UgPT0gIkVuZ2xhbmQiKSAlPiUgCiAgZ3JvdXBfYnkobG9jYWxfYXV0aG9yaXR5KSAlPiUKICBzdW1tYXJpc2UobWVhbl92aXNpdHMgPSBtZWFuKHZpc2l0cykpICU+JSAKICBnZ3Bsb3QoYWVzKGZpbGwgPSBtZWFuX3Zpc2l0cykpICsgCiAgZ2VvbV9zZihjb2xvdXIgPSAid2hpdGUiLCBsaW5ld2lkdGggPSAwLjA0KSArCiAgbGFicygKICAgIHggPSAiTG9uZ2l0dWRlIiwKICAgIHkgPSAiTGF0aXR1ZGUiLAogICAgdGl0bGUgPSAiQXZlcmFnZSBBbm51YWwgTnVtYmVyIG9mIEVuZ2xpc2ggQmFzZWQgVmlzdG9ycyIsCiAgICBzdWJ0aXRsZSA9ICJCeSBSZWdpb24iLAogICAgZmlsbCA9ICJWaXNpdHMgKFRob3VzYW5kcykiKSArCiAgdGhlbWUocGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIndoaXRlIiksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICByZWN0ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCkpCmBgYAoKIyMjIyBNYXJrZXRpbmcgRWRpbmJ1cmdoIHRvIERvbWVzdGljIFRvdXJpc3RzOiBNaW5pIENhc2UgU3R1ZHkKCiMjIyMjIFZpc2l0cyBieSBDb3VudHJ5IG9mIFJlc2lkZW5jZQoKYGBge3J9CnJlZ2lvbmFsX2RvbWVzdGljX3RvdXJpc21fbm9uX2diX2NsZWFuICU+JQogIGZpbHRlcihsb2NhbF9hdXRob3JpdHkgJWluJSBjKCJDaXR5IG9mIEVkaW5idXJnaCIpKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gdmlzaXRzLCB5ID0gcmVnaW9uX29mX3Jlc2lkZW5jZSwgZmlsbCA9IHJlZ2lvbl9vZl9yZXNpZGVuY2UgPT0gIlNjb3RsYW5kIikpICsKICBnZW9tX2RlbnNpdHlfcmlkZ2VzKHNob3cubGVnZW5kID0gRkFMU0UsIGFscGhhID0gMC41KSArCiAgdGhlbWVfcmlkZ2VzKCkgKwogIHRoZW1lKGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIkZBTFNFIiA9IGNvbG91cl9zY2hlbWVbMl0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVFJVRSIgPSBjb2xvdXJfc2NoZW1lWzFdKSkgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgQW5udWFsIFZpc2l0cyBieSBDb3VudHJ5IG9mIFJlc2lkZW5jZSIsCiAgICBzdWJ0aXRsZSA9ICJFZGluYnVyZ2giLAogICAgeCA9ICJWaXNpdHMgKFRob3VzYW5kcykiKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUsIGZhY2UgPSAiYm9sZCIpLAogICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEzKSwKICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiKSwKICAgICAgICBwYW5lbC5ncmlkID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJncmV5OTAiLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiKSkKYGBgCgojIyMjIyBFeHBlbmRpdHVyZSBQZXIgVmlzaXQgYnkgQ291bnRyeSBvZiBSZXNpZGVuY2UKCmBgYHtyfQpyZWdpb25hbF9kb21lc3RpY190b3VyaXNtX25vbl9nYl9jbGVhbiAlPiUKICBmaWx0ZXIobG9jYWxfYXV0aG9yaXR5ICVpbiUgYygiQ2l0eSBvZiBFZGluYnVyZ2giKSkgJT4lCiAgbXV0YXRlKGV4cF9wZXJfdmlzaXQgPSBleHBlbmRpdHVyZSAvIHZpc2l0cykgJT4lIAogIGdncGxvdChhZXMoeCA9IGV4cF9wZXJfdmlzaXQsIHkgPSByZWdpb25fb2ZfcmVzaWRlbmNlLCBmaWxsID0gcmVnaW9uX29mX3Jlc2lkZW5jZSA9PSAiU2NvdGxhbmQiKSkgKwogIGdlb21fZGVuc2l0eV9yaWRnZXMoc2hvdy5sZWdlbmQgPSBGQUxTRSwgYWxwaGEgPSAwLjUpICsKICB0aGVtZV9yaWRnZXMoKSArCiAgdGhlbWUoYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiRkFMU0UiID0gY29sb3VyX3NjaGVtZVsyXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJUUlVFIiA9IGNvbG91cl9zY2hlbWVbMV0pKSArCiAgbGFicygKICAgIHRpdGxlID0gIkRpc3RyaWJ1dGlvbiBvZiBFeHBlbmRpdHVyZSBwZXIgVmlzaXQgYnkgQ291bnRyeSBvZiBSZXNpZGVuY2UiLAogICAgc3VidGl0bGUgPSAiRWRpbmJ1cmdoIiwKICAgIHggPSAiRXhwZW5kaXR1cmUgcGVyIFZpc2l0IChNaWxsaW9uIEdCUCAvIFRob3VzYW5kIFZpc2l0cykiKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUsIGZhY2UgPSAiYm9sZCIpLAogICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEzKSwKICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiKSwKICAgICAgICBwYW5lbC5ncmlkID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJncmV5OTAiLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiKSkKYGBgCgojIyMjIyBOaWdodHMgYnkgQ291bnRyeSBvZiBSZXNpZGVuY2UKCmBgYHtyfQpyZWdpb25hbF9kb21lc3RpY190b3VyaXNtX25vbl9nYl9jbGVhbiAlPiUKICBmaWx0ZXIobG9jYWxfYXV0aG9yaXR5ICVpbiUgYygiQ2l0eSBvZiBFZGluYnVyZ2giKSkgJT4lIAogIG11dGF0ZShuaWdodHNfcGVyX3Zpc2l0ID0gbmlnaHRzIC8gdmlzaXRzKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBuaWdodHNfcGVyX3Zpc2l0LCB5ID0gcmVnaW9uX29mX3Jlc2lkZW5jZSwgZmlsbCA9IHJlZ2lvbl9vZl9yZXNpZGVuY2UgPT0gIlNjb3RsYW5kIikpICsKICBnZW9tX2RlbnNpdHlfcmlkZ2VzKHNob3cubGVnZW5kID0gRkFMU0UsIGFscGhhID0gMC41KSArCiAgdGhlbWVfcmlkZ2VzKCkgKwogIHRoZW1lKGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIkZBTFNFIiA9IGNvbG91cl9zY2hlbWVbMl0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVFJVRSIgPSBjb2xvdXJfc2NoZW1lWzFdKSkgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgTmlnaHRzIGJ5IENvdW50cnkgb2YgUmVzaWRlbmNlIiwKICAgIHN1YnRpdGxlID0gIkVkaW5idXJnaCIsCiAgICB4ID0gIk5pZ2h0cyIpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSwgZmFjZSA9ICJib2xkIiksCiAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTMpLAogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIpLAogICAgICAgIHBhbmVsLmdyaWQgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImdyZXk5MCIsIGxpbmV0eXBlID0gImRhc2hlZCIpLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIpKQpgYGAKCgojIyMjIyBMaW5lYXIgTW9kZWw6IFByZWRpY3QgRXhwZW5kaXR1cmUgYnkgVmlzaXRzCgpgYGB7cn0KcmVnaW9uYWxfZG9tZXN0aWNfdG91cmlzbV9ub25fZ2JfY2xlYW4gJT4lIAogIGZpbHRlcihsb2NhbF9hdXRob3JpdHkgPT0gIkNpdHkgb2YgRWRpbmJ1cmdoIiwKICAgICAgICAgcmVnaW9uX29mX3Jlc2lkZW5jZSA9PSAiRW5nbGFuZCIpICU+JSAKICBzdW1tYXJpc2UoY29yKGV4cGVuZGl0dXJlLCB2aXNpdHMpKQpgYGAKCmBgYHtyfQplZGluYnVyZ2hfZW5nbGFuZCA8LSByZWdpb25hbF9kb21lc3RpY190b3VyaXNtX25vbl9nYl9jbGVhbiAlPiUgCiAgZmlsdGVyKGxvY2FsX2F1dGhvcml0eSA9PSAiQ2l0eSBvZiBFZGluYnVyZ2giLAogICAgICAgICByZWdpb25fb2ZfcmVzaWRlbmNlID09ICJFbmdsYW5kIikKYGBgCgpgYGB7cn0KbW9kZWxfZWRpbmJ1cmdoIDwtIGxtKGZvcm11bGEgPSBleHBlbmRpdHVyZSB+IHZpc2l0cywgZGF0YSA9IGVkaW5idXJnaF9lbmdsYW5kKQpzdW1tYXJ5KG1vZGVsX2VkaW5idXJnaCkKYGBgCgpgYGB7cn0KYXV0b3Bsb3QobW9kZWxfZWRpbmJ1cmdoKQpgYGAKCi0gUmVzaWR1YWxzIHZzLiBGaXR0ZWQgKFRlc3RzIEluZGVwZW5kZW5jZSBvZiBSZXNpZHVhbHMpOiBObyBzdHJvbmcgZXZpZGVuY2Ugb2YgYSBwYXR0ZXJuLiAKLSBOb3JtYWwgUS1RIChUZXN0cyBOb3JtYWxpdHkgb2YgUmVzaWR1YWxzKTogRGlzdHJpYnV0aW9uIG9mIHN0YW5kYXJkaXNlZCByZXNpZHVhbHMgYXBwZWFycyBmYWlybHkgbm9ybWFsLiAKLSBTY2FsZS1Mb2NhdGlvbiAoVGVzdHMgQ29uc3RhbmN5IG9mIFZhcmlhdGlvbiBvZiBSZXNpZHVhbHMpOiBObyBzdHJvbmcgZXZpZGVuY2Ugb2YgZnVubmVsaW5nLgoKYGBge3J9CmVkaW5idXJnaF9lbmdsYW5kICU+JQogIGFkZF9wcmVkaWN0aW9ucyhtb2RlbF9lZGluYnVyZ2gpICU+JQogIGFkZF9yZXNpZHVhbHMobW9kZWxfZWRpbmJ1cmdoKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gdmlzaXRzLCB5ID0gZXhwZW5kaXR1cmUpKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX2xpbmUoYWVzKHkgPSBwcmVkKSwgY29sID0gY29sb3VyX3NjaGVtZVszXSwgc2l6ZSA9IDEpICsKICBsYWJzKAogICAgeCA9ICJWaXNpdHMgKFRob3VzYW5kcykiLAogICAgeSA9ICJFeHBlbmRpdHVyZSAoTWlsbGlvbiBHQlApIiwKICAgIHRpdGxlID0gIkVuZ2xpc2ggQmFzZWQgVmlzaXRvcnMgVG8gRWRpbmJ1cmdoOiBFeHBlbmRpdHVyZSAvIFZpc2l0cyIsCiAgICBzdWJ0aXRsZSA9ICJCYXNlZCBPbiAzIFllYXIgQW5udWFsIEF2ZXJhZ2VzIEJldHdlZW4gMjAwOS0yMDE5IikKYGBgCk1vZGVsOiBzcGVuZCB+IHZpc2l0cwoKSW50ZXJwcmV0YXRpb246IH45NyUgb2YgdGhlIHZhcmlhdGlvbiBpbiBleHBlbmRpdHVyZSBjYW4gYmUgZXhwbGFpbmVkIGJ5IHRoZSBudW1iZXIgb2YgdmlzaXRzLiAKClF1ZXN0aW9uOiBUaGUgbGFyZ2VzdCBpbmNyZWFzZSBpbiB2aXNpdG9yIG51bWJlcnMgaXMgZnJvbSAyMDA5LTIwMTEgQXZnLiB0byAyMDEwLTIwMTIgQXZnLiB+NiUuIElmIHRoaXMgcGVyY2VudGFnZSBpbmNyZWFzZSBpbiB2aXNpdHMgd2FzIHJlcGxpY2F0ZWQgaW4gYmFzZWQgb24gdGhlIG1vc3QgcmVjZW50IHNldCBvZiBmaWd1cmVzIHJlc3VsdGluZyBpbiB+MTgwMyAoVGhvdXNhbmQpIHZpc2l0b3JzIC0gd2hhdCB3b3VsZCB0aGUgbW9kZWwgcHJlZGljdCBmb3IgZXhwZW5kaXR1cmU/CgpBbnN3ZXI6IElmIHZpc2l0cyB3ZXJlIGluY3JlYXNlZCBhcyBhYm92ZSwgdGhlIG1vZGVsIHdvdWxkIHByZWRpY3QgZXhwZW5kaXR1cmUgb2YgfjYzMiBNaWxsaW9uIEdCUCAoTG93IEVzdGltYXRlIH42MjAsIEhpZ2ggRXN0aW1hdGUgfjY0NCkKCkFzIGNhbGN1bGF0ZWQgYmVsb3cuCgpTdGVwIDEuCm91dGNvbWUgPSBiMCArIGIxICogMXN0IFByZWRpY3RvcgoKU3RlcCAyLgpleHBlbmRpdHVyZSA9IGIwKGludGVyY2VwdCkgKyBiMShjb2VmZmljaWVudCkgKiAxc3QgUHJlZGljdG9yCgpTdGVwIDMuCmV4cGVuZGl0dXJlID0gYjAoaW50ZXJjZXB0KSArIGIxKGNvZWZmaWNpZW50KSAqIGB2aXNpdHNgCgpTdGVwIDQuCmV4cGVuZGl0dXJlID0gLTQ5My42MTc0OSArIDAuNjI0MjMgKiBgMTgwM2AKClN0ZXAgNS4KZXhwZW5kaXR1cmUgPSB+NjMyIChMb3cgRXN0aW1hdGUgfjYyMCwgSGlnaCBFc3RpbWF0ZSB+NjQ0KQoKYGBge3J9CjYzMiArIGMoLTEyLjM0LCAxMi4zNCkKYGBgCgojIyBJbnRlcm5hdGlvbmFsIFRvdXJpc20KCiMjIyBUb3RhbCBWaXNpdG9ycyBieSBDb3VudHJ5IG9mIFJlc2lkZW5jZQoKYGBge3J9CmludGVybmF0aW9uYWxfdmlzaXRzICU+JSAKICBzZWxlY3QoLWMocXVhcnRlciwgYWdlLCBzYW1wbGUpKSAlPiUKICBmaWx0ZXIoeWVhciAlaW4lIGMoMjAwOSwgMjAxMCwgMjAxMSwgMjAxMiwgMjAxMywgMjAxNCwgMjAxNSwgMjAxNiwgMjAxNywgMjAxOCwgMjAxOSksCiAgICAgICAgIHB1cnBvc2UgPT0gIkhvbGlkYXkiKSAlPiUgCiAgZ3JvdXBfYnkoY291bnRyeSkgJT4lIAogIHN1bW1hcmlzZSh0b3RhbF92aXNpdHMgPSBzdW0odmlzaXRzKSkgJT4lCiAgc2xpY2VfbWF4KHRvdGFsX3Zpc2l0cywgbiA9IDIwKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gcmVvcmRlcihjb3VudHJ5LCB0b3RhbF92aXNpdHMpLCB5ID0gdG90YWxfdmlzaXRzKSkgKwogIGdlb21fY29sKGFlcyh4ID0gcmVvcmRlcihjb3VudHJ5LCB0b3RhbF92aXNpdHMpLCB5ID0gdG90YWxfdmlzaXRzLAogICAgICAgICAgICAgICBmaWxsID0gY291bnRyeSAlaW4lIGMoIlVTQSIpKSwKICAgICAgICAgICBzaG93LmxlZ2VuZCA9IEZBTFNFLCBjb2xvdXIgPSAid2hpdGUiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiRkFMU0UiID0gImdyZXk2MCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVFJVRSIgPSBjb2xvdXJfc2NoZW1lWzFdKSkgKwogIGNvb3JkX2ZsaXAoKSArCiAgeWxpbSgwLCAzMjAwKSArCiAgbGFicygKICAgIHggPSAiQ291bnRyeSIsCiAgICB5ID0gIlRvdGFsIFZpc2l0cyAoVGhvdXNhbmRzKSIsCiAgICB0aXRsZSA9ICJJbnRlcm5hdGlvbmFsIFRvdXJpc206IFRvdGFsIFZpc2l0cyAoMjAwMi0yMDA5KSIsCiAgICBzdWJ0aXRsZSA9ICJUb3AgMjAgKEhvbGlkYXkgT25seSkiKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUsIGZhY2UgPSAiYm9sZCIpLAogICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwKICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiKSwKICAgICAgICBwYW5lbC5ncmlkID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJncmV5OTAiLCBsaW5ldHlwZSA9ICJibGFuayIpKQpgYGAKCiMjIyBUb3RhbCBFeHBlbmRpdHVyZSBieSBDb3VudHJ5IG9mIFJlc2lkZW5jZQoKYGBge3J9CmludGVybmF0aW9uYWxfdmlzaXRzICU+JSAKICBzZWxlY3QoLWMocXVhcnRlciwgYWdlLCBzYW1wbGUpKSAlPiUKICBmaWx0ZXIoeWVhciAlaW4lIGMoMjAwOSwgMjAxMCwgMjAxMSwgMjAxMiwgMjAxMywgMjAxNCwgMjAxNSwgMjAxNiwgMjAxNywgMjAxOCwgMjAxOSksCiAgICAgICAgIHB1cnBvc2UgPT0gIkhvbGlkYXkiKSAlPiUgCiAgZ3JvdXBfYnkoY291bnRyeSkgJT4lIAogIHN1bW1hcmlzZSh0b3RhbF9zcGVuZCA9IHN1bShzcGVuZCkpICU+JQogIHNsaWNlX21heCh0b3RhbF9zcGVuZCwgbiA9IDIwKSAlPiUgCiAgZ2dwbG90KCkgKwogIGdlb21fY29sKGFlcyh4ID0gcmVvcmRlcihjb3VudHJ5LCB0b3RhbF9zcGVuZCksIHkgPSB0b3RhbF9zcGVuZCwKICAgICAgICAgICAgICAgZmlsbCA9IGNvdW50cnkgJWluJSBjKCJVU0EiKSksCiAgICAgICAgICAgc2hvdy5sZWdlbmQgPSBGQUxTRSwgY29sb3VyID0gIndoaXRlIikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIkZBTFNFIiA9ICJncmV5NjAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRSVUUiID0gY29sb3VyX3NjaGVtZVsxXSkpICsKICBjb29yZF9mbGlwKCkgKwogIGxhYnMoCiAgICB4ID0gIkNvdW50cnkiLAogICAgeSA9ICJUb3RhbCBFeHBlbmRpdHVyZSAoTWlsbGlvbiBHQlApIiwKICAgIHRpdGxlID0gIkludGVybmF0aW9uYWwgVG91cmlzbTogVG90YWwgRXhwZW5kaXR1cmUgKDIwMDItMjAwOSkiLAogICAgc3VidGl0bGUgPSAiVG9wIDIwIChIb2xpZGF5IE9ubHkpIikgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1LCBmYWNlID0gImJvbGQiKSwKICAgICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIndoaXRlIiksCiAgICAgICAgcGFuZWwuZ3JpZCA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiZ3JleTkwIiwgbGluZXR5cGUgPSAiYmxhbmsiKSkKYGBgCgojIyMgRXhwZW5kaXR1cmUgcGVyIFZpc2l0IGJ5IENvdW50cnkgb2YgUmVzaWRlbmNlCgojIyMjIEJhciBQbG90CgpgYGB7cn0KaW50ZXJuYXRpb25hbF92aXNpdHMgJT4lIAogIHNlbGVjdCgtYyhxdWFydGVyLCBhZ2UsIHNhbXBsZSkpICU+JQogIGZpbHRlcih5ZWFyICVpbiUgYygyMDA5LCAyMDEwLCAyMDExLCAyMDEyLCAyMDEzLCAyMDE0LCAyMDE1LCAyMDE2LCAyMDE3LCAyMDE4LCAyMDE5KSwKICAgICAgICAgcHVycG9zZSA9PSAiSG9saWRheSIpICU+JSAKICBncm91cF9ieShjb3VudHJ5KSAlPiUgCiAgc3VtbWFyaXNlKHRvdGFsX3NwZW5kID0gc3VtKHNwZW5kKSwKICAgICAgICAgICAgdG90YWxfdmlzaXRzID0gc3VtKHZpc2l0cyksCiAgICAgICAgICAgIHNwZW5kX3Blcl92aXNpdCA9IHRvdGFsX3NwZW5kIC8gdG90YWxfdmlzaXRzKSAlPiUKICBmaWx0ZXIodG90YWxfdmlzaXRzID4gNTAwKSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9jb2woYWVzKHggPSByZW9yZGVyKGNvdW50cnksIHNwZW5kX3Blcl92aXNpdCksIHkgPSBzcGVuZF9wZXJfdmlzaXQsCiAgICAgICAgICAgICAgIGZpbGwgPSBjb3VudHJ5ICVpbiUgYygiQXVzdHJhbGlhIiwgIkNoaW5hIiwgIkNhbmFkYSIpKSwKICAgICAgICAgICBzaG93LmxlZ2VuZCA9IEZBTFNFLCBjb2xvdXIgPSAid2hpdGUiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiRkFMU0UiID0gImdyZXk2MCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVFJVRSIgPSBjb2xvdXJfc2NoZW1lWzFdKSkgKwogIGNvb3JkX2ZsaXAoKSArCiAgbGFicygKICAgIHggPSAiQ291bnRyeSIsCiAgICB5ID0gIlRvdGFsIEV4cGVuZGl0dXJlIChNaWxsaW9uIEdCUCkgLyBUb3RhbCBWaXNpdHMgKFRob3VzYW5kcykiLAogICAgdGl0bGUgPSAiSW50ZXJuYXRpb25hbCBUb3VyaXNtOiBUb3RhbCBFeHBlbmRpdHVyZSBwZXIgVmlzaXQgKDIwMDItMjAwOSkiLAogICAgc3VidGl0bGUgPSAiQ291bnRyaWVzIHcvIE92ZXIgNTAwIFRob3VzYW5kIFRvdGFsIFZpc2l0cyAoSG9saWRheSBPbmx5KSIpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSwgZmFjZSA9ICJib2xkIiksCiAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIpLAogICAgICAgIHBhbmVsLmdyaWQgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImdyZXk5MCIsIGxpbmV0eXBlID0gImJsYW5rIikpCmBgYAoKIyMjIyBTY2F0dGVyIFBsb3QKCmBgYHtyfQppbnRlcm5hdGlvbmFsX3Zpc2l0cyAlPiUgCiAgc2VsZWN0KC1jKHF1YXJ0ZXIsIGFnZSwgc2FtcGxlKSkgJT4lCiAgZmlsdGVyKHllYXIgJWluJSBjKDIwMDksIDIwMTAsIDIwMTEsIDIwMTIsIDIwMTMsIDIwMTQsIDIwMTUsIDIwMTYsIDIwMTcsIDIwMTgsIDIwMTkpLAogICAgICAgICBwdXJwb3NlID09ICJIb2xpZGF5IikgJT4lIAogIGdyb3VwX2J5KGNvdW50cnkpICU+JSAKICBzdW1tYXJpc2UodG90YWxfc3BlbmQgPSBzdW0oc3BlbmQpLAogICAgICAgICAgICB0b3RhbF92aXNpdHMgPSBzdW0odmlzaXRzKSwKICAgICAgICAgICAgc3BlbmRfcGVyX3Zpc2l0ID0gdG90YWxfc3BlbmQgLyB0b3RhbF92aXNpdHMpICU+JQogIGZpbHRlcih0b3RhbF92aXNpdHMgPiA1MDApICU+JSAKICBnZ3Bsb3QoYWVzKHggPSB0b3RhbF92aXNpdHMsIHkgPSBzcGVuZF9wZXJfdmlzaXQpKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3VyID0gY291bnRyeSAlaW4lIGMoIkF1c3RyYWxpYSIsICJDaGluYSIsICJDYW5hZGEiKSksIAogICAgICAgICAgICAgc2hvdy5sZWdlbmQgPSBGQUxTRSwKICAgICAgICAgICAgIHNpemUgPSA0KSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJGQUxTRSIgPSAiZ3JleTYwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRSVUUiID0gY29sb3VyX3NjaGVtZVszXSkpICsKICBnZ3JlcGVsOjpnZW9tX3RleHRfcmVwZWwoYWVzKHggPSB0b3RhbF92aXNpdHMsIHkgPSBzcGVuZF9wZXJfdmlzaXQsIGxhYmVsID0gY291bnRyeSkpICsKICBsYWJzKAogICAgeCA9ICJWaXNpdHMgKFRob3VzYW5kcykiLAogICAgeSA9ICJUb3RhbCBFeHBlbmRpdHVyZSAoTWlsbGlvbiBHQlApIC8gVG90YWwgVmlzaXRzIChUaG91c2FuZHMpIiwKICAgIHRpdGxlID0gIkludGVybmF0aW9uYWwgVG91cmlzbTogVmlzaXRzIHZzLiBFeHBlbmRpdHVyZSBQZXIgVmlzaXQgKDIwMDItMjAwOSkiLAogICAgc3VidGl0bGUgPSAiQ291bnRyaWVzIHcvIE92ZXIgNTAwIFRob3VzYW5kIFRvdGFsIFZpc2l0cyAoSG9saWRheSBPbmx5KSIpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSwgZmFjZSA9ICJib2xkIiksCiAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIpLAogICAgICAgIHBhbmVsLmdyaWQgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImdyZXk5MCIsIGxpbmV0eXBlID0gImRhc2hlZCIpKQpgYGAKCiMjIyBNYXJrZXRpbmcgU2NvdGxhbmQgVG8gQ2FuYWRpYW4gQmFzZWQgVG91cmlzdHMKCiRIXzAkOiAkXG11X3tcdGV4dHJte3NwZW5kIHBlciB2aXNpdChRMStRNCl9fSAtIFxtdV97XHRleHRybXtzcGVuZCBwZXIgdmlzaXQoUTIrUTMpfX0gPSAwJAokSF9hJDogJFxtdV97XHRleHRybXtzcGVuZCBwZXIgdmlzaXQoUTErUTQpfX0gLSBcbXVfe1x0ZXh0cm17c3BlbmQgcGVyIHZpc2l0KFEyK1EzKX19ICE9IDAkCgpgYGB7cn0KaW50ZXJuYXRpb25hbF92aXNpdHMgJT4lCiAgZmlsdGVyKGNvdW50cnkgPT0gIkNhbmFkYSIsCiAgICAgICAgIHB1cnBvc2UgPT0gIkhvbGlkYXkiKSAlPiUgCiAgbXV0YXRlKGV4cF9wZXJfdmlzaXQgPSBzcGVuZCAvIHZpc2l0cywKICAgICAgICAgc3ByaW5nX3N1bW1lciA9IGlmX2Vsc2UocXVhcnRlciAlaW4lIGMoIlF1YXJ0ZXIgMiIsICJRdWFydGVyIDMiKSwgIlllcyIsICJObyIpKSAlPiUgIAogIGdyb3VwX2J5KHNwcmluZ19zdW1tZXIpICU+JSAKICBzdW1tYXJpc2UobWVhbl92aXNpdHMgPSBtZWFuKHZpc2l0cyksCiAgICAgICAgICAgIG1lYW5fZXhwID0gbWVhbihzcGVuZCksCiAgICAgICAgICAgIG1lYW5fZXhwX3Blcl92aXNpdCA9IG1lYW4oZXhwX3Blcl92aXNpdCkpCmBgYApgYGB7cn0KY2FuYWRhX3NhbXBsZSA8LSBpbnRlcm5hdGlvbmFsX3Zpc2l0cyAlPiUKICBmaWx0ZXIoY291bnRyeSA9PSAiQ2FuYWRhIiwKICAgICAgICAgcHVycG9zZSA9PSAiSG9saWRheSIpICU+JSAKICBtdXRhdGUoZXhwX3Blcl92aXNpdCA9IHNwZW5kIC8gdmlzaXRzLAogICAgICAgICBzcHJpbmdfc3VtbWVyID0gaWZfZWxzZShxdWFydGVyICVpbiUgYygiUXVhcnRlciAyIiwgIlF1YXJ0ZXIgMyIpLCAiWWVzIiwgIk5vIikpCmBgYAoKYGBge3J9Cm9ic2VydmVkX3N0YXQgPC0gY2FuYWRhX3NhbXBsZSAlPiUgCiAgc3BlY2lmeShleHBfcGVyX3Zpc2l0IH4gc3ByaW5nX3N1bW1lcikgJT4lCiAgY2FsY3VsYXRlKHN0YXQgPSAiZGlmZiBpbiBtZWFucyIsIG9yZGVyID0gYygiWWVzIiwgIk5vIikpCgpvYnNlcnZlZF9zdGF0CmBgYAoKYGBge3J9Cm51bGxfZGlzdHJpYnV0aW9uIDwtIGNhbmFkYV9zYW1wbGUgJT4lIAogIHNwZWNpZnkocmVzcG9uc2UgPSBleHBfcGVyX3Zpc2l0LCBleHBsYW5hdG9yeSA9IHNwcmluZ19zdW1tZXIpICU+JQogIGh5cG90aGVzaXplKG51bGwgPSAiaW5kZXBlbmRlbmNlIikgJT4lCiAgZ2VuZXJhdGUocmVwcyA9IDEwMDAsIHR5cGUgPSAicGVybXV0ZSIpICU+JSAKICBjYWxjdWxhdGUoc3RhdCA9ICJkaWZmIGluIG1lYW5zIiwgb3JkZXIgPSBjKCJZZXMiLCAiTm8iKSkKYGBgCgpgYGB7cn0KbnVsbF9kaXN0cmlidXRpb24gJT4lCiAgdmlzdWFsaXNlKCkgKwogIHNoYWRlX3BfdmFsdWUob2JzX3N0YXQgPSBvYnNlcnZlZF9zdGF0LCBkaXJlY3Rpb24gPSAiYm90aCIpCmBgYAoKYGBge3J9Cm51bGxfZGlzdHJpYnV0aW9uICU+JQogIGdldF9wX3ZhbHVlKG9ic19zdGF0ID0gb2JzZXJ2ZWRfc3RhdCwgZGlyZWN0aW9uID0gImJvdGgiKQpgYGAKCg==